using System;
using System.Collections.Generic;
using System.Reflection;

namespace Cz
{
    public class CzFactory
    {
        private readonly Dictionary<string, ICzBase> nameDict = new Dictionary<string, ICzBase>();
        private readonly Dictionary<Type, ICzBase> typeDict = new Dictionary<Type, ICzBase>();
        private readonly LinkedList<ICzBase> allServices = new LinkedList<ICzBase>();
        
        private bool started = false;

        #region 添加服务
        public T AddService<T>(T service, string name = null) where T : ICzBase
        {
            if(!string.IsNullOrEmpty(name))
                nameDict[name] = service;
            return AddService(service);
        }
        
        private T AddService<T>(T service) where T : ICzBase
        {
            var baseType = service.GetServiceType();
            typeDict[baseType] = service;
            allServices.AddLast(service);

            return service;
        }
        #endregion

        #region 获取服务
        public ICzBase GetService(string name, bool canNull = false)
        {
            if(nameDict.TryGetValue(name, out var ret))
            {
                return ret;
            }

            if (canNull)
                return null;
            throw new Exception("缺少服务:" + name);
        }
        
        public ICzBase GetService(Type baseType, bool canNull = false)
        {
            if(typeDict.TryGetValue(baseType, out var ret))
            {
                return ret;
            }
            if (canNull)
                return null;
            throw new Exception("缺少服务:" + baseType.Name);
        }
        
        public ICzBase GetService<T>(bool canNull = false) where T : ICzBase
        {
            var baseType = typeof(T).GetServiceType();
            if(typeDict.TryGetValue(baseType, out var ret))
            {
                return ret;
            }
            if (canNull)
                return null;
            throw new Exception("缺少服务:" + baseType.Name);
        }
        #endregion

        #region 启动服务
        public void Start()
        {
            if(started)
                throw new Exception("重复启动!");

            started = true;
            
            foreach (var service in allServices)
            {
                StartService(service);
            }
        }

        public void StartService(ICzBase service)
        {
            var fields = service.GetType()
                .GetFields(~BindingFlags.Static);

            // 依赖注入
            foreach (var field in fields)
            {
                var att = field.GetCustomAttribute<CzServiceField>();
                if (att != null)
                {
                    field.SetValue(service,
                        string.IsNullOrEmpty(att.name) ? GetService(field.FieldType, att.canNull) : GetService(att.name, att.canNull));
                }
            }
            
            service.Start();
        }
        #endregion
    }
}